iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 15
0
Mobile Development

RxSwift / 30天探索之旅系列 第 15

第 15 天 - Combining Observables(下)

  • 分享至 

  • xImage
  •  

嗨嗨,今天第15天,已經超過一半了阿!今天繼續講Combining Observables。

Zip

zipmergecombineLatest也很相似,不同在於發出的時機,zip發出的時機是相同位置的元素一同發送,1st對應1st、2nd對應2nd、依此類推,當你需要兩個 resource(或多個)同時出現,那就選擇zip了!

我們拿 combineLatest 範例,只將operator換成zip,來看看結果有什麼不同

let one = PublishSubject<String>()
let two = PublishSubject<Int>()

let result = Observable.zip(one, two) { str, number in
    return "\(str), \(number)"
}

result
    .subscribe(onNext: {
        print($0)
    })
    .disposed(by: disposeBag)

one.onNext("Koala")
two.onNext(2)
one.onNext("Penguin")
one.onNext("Monkey")
two.onNext(7)

執行結果

Koala, 2
Penguin, 7
  1. Koala數字2都是Observable的第一個元素,所以被配再一起了
  2. Penguin數字7都是2nd,儘管中間還有Monkey,也不會受影響
  3. 一樣可以省略closure,執行結果就會變這樣
("Koala", 2)
("Penguin", 7)

WithLatestFrom

withLatestFrom也是去合併最新的元素,就以這概念來說,跟combineLatest有點像,但不同之處在於, withLatestFrom是以一條Observable為主,去接收另一條Observable最新的值,常見情境就是button的tap事件去合併某Observable,藉此取的最新元素作為參數,再去呼叫 API,大概會像這樣

// ViewController
button.rx.tap.bind(to: viewModel.observer)

// ViewModel
let subject = PublishSubject<Void>()
observer = subject.asObserver()

subject.asObservable()
    .withLatestFrom(neededData)
    .flatMapLatest { API().request().asObservable().materialize() }
    .share() // Void -> neededData Element

下面就先以簡單範例,來展示withLatestFrom,因為怕有點難懂,我們在附上圖解。

let one = PublishSubject<String>()
let two = PublishSubject<Int>()

let result = one.withLatestFrom(two) { str, number in
    return "\(str), \(number)"
}

result
    .subscribe(onNext: {
        print($0)
    })
    .disposed(by: disposeBag)

one.onNext("Koala")
two.onNext(2)
one.onNext("Penguin")
one.onNext("Monkey")
two.onNext(7)
one.onNext("Chicken")

圖解如下
https://ithelp.ithome.com.tw/upload/images/20200929/201157517voAjRed6x.png

  1. one為主,當發出Koala的時候,這時會去合two的最新元素,但two還沒發出任何元素,所以這時並不會發生任何事情
  2. two發出數字2的時候,也不會發生任何事情
  3. 當發出Penguin,這時會去合併two的最新元素數字2
  4. 當發出Monkey,這時還是去合併two的最新元素數字2
  5. 當發出Chicken,這時的two最新元素是數字7,所以合併數字7

執行結果如下

Penguin, 2
Monkey, 2
Chicken, 7

Amb

RxSwift提供兩種方式來切換Observable,讓你在Run time的時候決定訂閱哪個Observable,第一個就是ambiguous,left.ambiguous(right)會有兩個Observable,接著,只訂閱第一個發送元素的Observable,取消訂閱另一個,ambiguous意思就是曖昧、模棱兩可、歧義的,就好像一開始你也不知道你喜歡誰,但是當第一個跟你告白的你就會接受(?)

let one = PublishSubject<String>()
let two = PublishSubject<String>()

let result = one.amb(two)

result
    .subscribe(onNext: {
        print($0)
    })
    .disposed(by: disposeBag)

one.onNext("A")
two.onNext("1")
one.onNext("B")
one.onNext("C")
two.onNext("2")
two.onNext("3")

執行結果

A
B
C

SwitchLatest

另外一個切換方式是switchLatest,不像ambswitchLatest不侷限有只有兩條,要切換不同的Observable ,只要發送型態相同的Observable給Xource subject,就可以了,下面展示簡單範例

let one = PublishSubject<String>()
let two = PublishSubject<String>()
let three = PublishSubject<String>()

// 1
let source = PublishSubject<Observable<String>>()

// 2
source.switchLatest()
    .subscribe(onNext: {
        print($0)
    })
    .disposed(by: disposeBag)

// 3
source.onNext(one)
one.onNext("A")
two.onNext("1")
three.onNext("Koala")

// 4
source.onNext(two)
one.onNext("B")
two.onNext("2")
one.onNext("Penguin")

source.onNext(three)
three.onNext("Monkey")
three.onNext("Chicken")
two.onNext("3")
  1. 建立一個名為source的Observable,他的元素必須也要是Observable<T>才行,這裡為Observable<String>
  2. 訂閱source.switchLatest(),來查看現在切換到的Observable的元素
  3. 當source接收到one時,現在只會接收one發送過來的元素
  4. 當source接收到two時,現在只會接收two發送過來的元素,依此類推

執行結果

A
2
Monkey
Chicken

講到這,switchLatestflatMapLatest很像啊?看書才知道原來flatMapLatest就是mapswitchLatest的結合,不過我基本上我都是使用flatMapLatest就是了。


大家會不會覺得,有幾個都好相似?
我一開始學的時候,flatLastestcombineLatestwithLatestFrom都亂用,反正可以跑就好了(誤),明天會統整一下operator使用時機,跟大家分享我自己用錯的經驗,給大家做個參考,就這樣,掰掰


上一篇
第 14 天 - Combining Observables(中)
下一篇
第 16 天 - 統整一下Operator的選擇
系列文
RxSwift / 30天探索之旅30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言